#include "campus_person_info_manager.h"
#include"../log/campus_logger.h"

CampusPersonInfoManager::CampusPersonInfoManager(CampusWholeServer* whole_server, CampusSqlConnector* sql_connector):
    whole_server_(whole_server),
    sql_connector_(sql_connector)
{
}

CampusPersonInfoManager::~CampusPersonInfoManager()
{
}

void CampusPersonInfoManager::handlePersonInfo(websocketpp::connection_hdl hdl, json const JMsg)
{
    try{
        std::string uid = JMsg["uid"];
        doPersonInfo(hdl, uid);
    }
    catch(...){
        CampusLogger::warn("CampusPersonInfoManager::handlePersonInfo error");
    }   
}

void CampusPersonInfoManager::handlePersonInfoModify(websocketpp::connection_hdl hdl, json const JMsg)
{
    try{
        std::vector<std::pair<std::string,std::string>> columns;

        for(auto it = JMsg.begin(); it != JMsg.end(); it++){
            if(it.key() == "cmd"){
                continue;
            }
            columns.push_back({it.key(), it.value()});
        }

        doPersonInfoModify(hdl, columns);
    }
    catch(...){
        CampusLogger::warn("CampusPersonInfoManager::handlePersonInfoModify error");
    }
}

void CampusPersonInfoManager::onSelectSucess(std::vector<std::vector<std::pair<std::string, std::string>>>& result,CampusSqlInfo* userData)
{
    CampusPersonInfo* p_info_ = dynamic_cast<CampusPersonInfo*>(userData);
    std::shared_ptr<CampusPersonInfo> p_info(p_info_); // 智能指针管理内存，避免泄漏
    enum CampusPersonInfoSqlType type = p_info->type;

    switch (type)
    {
    case PERSON_INFO_SQL_SELECT:
        handlePersonInfoSelect(p_info->hdl, result);
        break;
    case PERSON_INFO_MODIFY_SQL_SELECT:
        handlePersonInfoModifySelect(p_info.get(), result);
        break;
    default:
        break;
    }
   
    printPersonInfo(p_info.get());
}

void CampusPersonInfoManager::onSelectFail(CampusSqlInfo* userData)
{
    CampusLogger::warn("CampusPersonInfoManager::onSelectFail error");
    printPersonInfo(dynamic_cast<CampusPersonInfo*>(userData));
}

void CampusPersonInfoManager::onUpdateSucess(CampusSqlInfo* userData)
{
    CampusLogger::info("CampusPersonInfoManager::onUpdateSucess sucess");
    
    CampusPersonInfo* p_info_ = dynamic_cast<CampusPersonInfo*>(userData);
    std::shared_ptr<CampusPersonInfo> p_info(p_info_); // 智能指针管理内存，避免泄漏

    enum CampusPersonInfoSqlType type = p_info->type;
    switch (type)
    {
    case PERSON_INFO_MODIFY_SQL_UPDATE:
        CampusLogger::info("CampusPersonInfoManager::onUpdatesucess sucess");
        doPersonInfoUpdated(p_info->hdl);
        break;
    default:
        CampusLogger::warn("CampusPersonInfoManager::onUpdatesucess error");
        break;
    }
}

void CampusPersonInfoManager::onUpdateFail(CampusSqlInfo* userData)
{
    CampusLogger::warn("CampusPersonInfoManager::onUpdateFail error");
    printPersonInfo(dynamic_cast<CampusPersonInfo*>(userData));
}

void CampusPersonInfoManager::onInsertSucess(CampusSqlInfo* userData)
{
    CampusLogger::info("CampusPersonInfoManager::onInsertsucess sucess");

    CampusPersonInfo* p_info_ = dynamic_cast<CampusPersonInfo*>(userData);
    std::shared_ptr<CampusPersonInfo> p_info(p_info_); // 智能指针管理内存，避免泄漏

    enum CampusPersonInfoSqlType type = p_info->type;
    switch (type)
    {
    case PERSON_INFO_MODIFY_SQL_INSERT:
        doPersonInfoInserted(userData);
        break;
    default:
        break;
    }

}
void CampusPersonInfoManager::onInsertFail(CampusSqlInfo* userData)
{
    CampusLogger::warn("CampusPersonInfoManager::onInsertFail error");
    printPersonInfo(dynamic_cast<CampusPersonInfo*>(userData));
}

void CampusPersonInfoManager::printPersonInfo(CampusPersonInfo* p_info)
{
    CampusLogger::info("---------------------------- Person Info ----------------------------");
    CampusLogger::info("SQL: {}", p_info->sql);
    CampusLogger::info("Type: {}", static_cast<int>(p_info->type));
    CampusLogger::info("UID: {}", p_info->uid);
    CampusLogger::info("Name: {}", p_info->name);
    CampusLogger::info("Class: {}", p_info->class_);
    CampusLogger::info("College: {}", p_info->college);
    CampusLogger::info("Gender: {}", p_info->gender);
    CampusLogger::info("Major: {}", p_info->major);
    CampusLogger::info("Identity: {}", p_info->identity);
    CampusLogger::info("UserData: {:p}", p_info->user_data);
    CampusLogger::info("HDL: {:p}", p_info->hdl.lock().get());
    CampusLogger::info("---------------------------------------------------------------------");
}

void CampusPersonInfoManager::handlePersonInfoSelect(websocketpp::connection_hdl hdl, std::vector<std::vector<std::pair<std::string, std::string>>> &result)
{
    json JMsg;
    JMsg["cmd"] = SIGNAL_TYPE_RESP_PERSON_INFO;
    
    if(result.empty()){
        CampusLogger::info("CampusPersonInfoManager::handlePersonInfoSelect not exists");
        JMsg["ret"] = PERSON_INFO_NOT_EXISTS;
    }
    else{
        CampusLogger::info("CampusPersonInfoManager::handlePersonInfoSelect sucess");
        JMsg["ret"] = PERSON_INFO_SUCESS;
        for(auto& item:result){
            for(auto& [key,value]:item){
                JMsg[key] = value;
            }
        }
    }

    whole_server_->send(hdl, JMsg.dump());
}

void CampusPersonInfoManager::handlePersonInfoModifySelect(CampusSqlInfo* userData, std::vector<std::vector<std::pair<std::string, std::string>>> &result)
{
    if(result.empty()){ //不存在就插入
        CampusLogger::info("CampusPersonInfoManager::handlePersonInfoModifySelect not exists");
        doInsertPersonInfo(userData);
    }
    else{ //存在就更新
        CampusLogger::info("CampusPersonInfoManager::handlePersonInfoModifySelect sucess");
        doUpdatePersonInfo(userData);
    }
}

void CampusPersonInfoManager::doPersonInfo(websocketpp::connection_hdl hdl, std::string const &uid)
{
    CampusLogger::info("CampusPersonInfoManager::doPersonInfo uid:{}",uid);
    
    std::string sql = "select * from person_info_t where uid = ?" ;
    std::vector<std::string>params = { uid };

    CampusPersonInfo* p_info = new CampusPersonInfo();
    p_info->type = CampusPersonInfoSqlType::PERSON_INFO_SQL_SELECT;
    p_info->hdl = hdl;
    p_info->uid = uid;
    p_info->sql = sql;

    sql_connector_->exec(sql, SELECT, params, static_cast<void*>(p_info));
}

void CampusPersonInfoManager::doPersonInfoModify(websocketpp::connection_hdl hdl, std::vector<std::pair<std::string,std::string>>& columns)
{
    CampusLogger::info("CampusPersonInfoManager::doPersonInfoModify ");
 
    std::string sql = "select * from person_info_t where uid = ?";
    std::vector<std::string>params;
    CampusPersonInfo* p_info = new CampusPersonInfo();
    
    p_info->type = PERSON_INFO_MODIFY_SQL_SELECT;
    p_info->hdl = hdl;
    for(auto& [key,value]:columns){
        if(key == "uid"){
            params.push_back(value);            
            p_info->uid = value;
        }
        else if(key == "name") p_info->name = value;
        else if(key == "class") p_info->class_ = value;
        else if(key == "college") p_info->college = value;
        else if(key == "major") p_info->major = value;
        else if(key == "gender") p_info->gender = value;
        else if(key == "identity")p_info->identity = value;
    }

    sql_connector_->exec(sql, SELECT, params, static_cast<void*>(p_info));
}

void CampusPersonInfoManager::doPersonInfoUpdated(websocketpp::connection_hdl hdl)
{
    CampusLogger::info("CampusPersonInfoManager::doPersonInfoUpdate hdl:{}",hdl.lock().get());
    
    json JMsg;
    JMsg["cmd"] = SIGNAL_TYPE_PERSON_INFO_MODIFY;
    JMsg["ret"] = PERSON_INFO_MODIFY_SUCESS;
    
    whole_server_->send(hdl,JMsg.dump());
}

void CampusPersonInfoManager::doPersonInfoInserted(CampusSqlInfo* userData)
{
    CampusLogger::info("CampusPersonInfoManager::doPersonInfoInserted");

    json JMsg;
    JMsg["cmd"] = SIGNAL_TYPE_PERSON_INFO_MODIFY;
    JMsg["ret"] = PERSON_INFO_MODIFY_SUCESS;
    
    whole_server_->send(userData->hdl, JMsg.dump());
}

void CampusPersonInfoManager::doInsertPersonInfo(CampusSqlInfo *userData)
{
    std::string sql = "insert into person_info_t (uid,name,class,college,major,gender,identity) values (?,?,?,?,?,?,?)";

    CampusPersonInfo* p_info = dynamic_cast<CampusPersonInfo*>(userData);
    std::vector<std::string> params = {
        p_info->name,
        p_info->class_,
        p_info->college,
        p_info->major,
        p_info->gender,
        p_info->identity,
        p_info->uid
    };

    CampusPersonInfo* p_info2 = new CampusPersonInfo();
    p_info2->type = PERSON_INFO_MODIFY_SQL_INSERT;
    p_info2->sql = sql;
    sql_connector_->exec(sql, INSERT, params, static_cast<void*>(p_info2));
}

void CampusPersonInfoManager::doUpdatePersonInfo(CampusSqlInfo *userData)
{
    std::string sql = "update person_info_t set name=?,class=?,college=?,major=?,gender=?,identity=? where uid=?";

    CampusPersonInfo* p_info = dynamic_cast<CampusPersonInfo*>(userData);

    std::vector<std::string> params = {
        p_info->name,
        p_info->class_,
        p_info->college,
        p_info->major,
        p_info->gender,
        p_info->identity,
        p_info->uid
    };

    CampusPersonInfo* p_info2 = new CampusPersonInfo(*p_info); //使用拷贝构造函数，而不是memcpy
    p_info2->type = PERSON_INFO_MODIFY_SQL_UPDATE;
    p_info2->sql = sql;
    
    sql_connector_->exec(sql, UPDATE, params, static_cast<void*>(p_info2));

    CampusLogger::info("CampusPersonInfoManager::doUpdatePersonInfo");
    printPersonInfo(p_info2);
}